﻿using System;
using System.Text;
using Library.OrmEnterpriseEntity.TableInfo;

namespace Library.OrmEnterpriseEntity {
	/// <summary>
	/// Perform SQL select statement
	/// </summary>
	public sealed class SelectQueryStatement : QueryStatement {
		protected internal ISelectOption SelectOption;

		public override int Excute() {
			return Excute(EmpltyCreator, 0);
		}
		private static readonly GlobalEntity.EntityCreator EmpltyCreator = new GlobalEntity.EntityCreator();
		internal SelectQueryStatement(GlobalEntityView root, StringBuilder sqlTracking)
			: base(root) {
			Statement = this;
			SqlTracking = sqlTracking;
		}
		/// <summary>
		/// Excute select statement
		/// </summary>
		/// <param name="creator"></param>
		public void Excute(GlobalEntity.EntityCreator creator) {
			Excute(creator, 0);
		}
		/// <summary>
		/// Excute statement with limited return row
		/// </summary>
		/// <param name="creator">EntityCreator</param>
		/// <param name="rowReturn">The expected return row number </param>
		/// <exception cref="ArgumentNullException">creator is null</exception>
		/// <returns>Return real total row effect</returns>
		public int Excute(GlobalEntity.EntityCreator creator, int rowReturn) {
			if (creator == null) throw new ArgumentNullException("creator");
			Creator = creator;
			return Root.ExcuteStatement(this, rowReturn);
		}
		/// <summary>
		/// Excute statement with paging control
		/// </summary>
		/// <param name="creator">EntityCreator</param>
		/// <param name="page">The index of page</param>
		/// <param name="pageSize">total item per page</param>
		/// <exception cref="ArgumentNullException">creator is null</exception>
		/// <returns>Total items found in select</returns>
		public int Excute(GlobalEntity.EntityCreator creator, int page, int pageSize) {
			if (creator == null) throw new ArgumentException("creator");
			Creator = creator;
			return Root.ExcuteStatement(this, page, pageSize);
		}




		/// <summary>
		/// Count clause
		/// </summary>
		/// <param name="column">Count column</param>
		/// <returns>SelectQueryStatement</returns>
		public SelectQueryStatement Count(DbColumnView column) {
			CountCol = column;
			return this;
		}
		/// <summary>
		/// Group clause
		/// </summary>
		/// <param name="columns">The list of columns in Group by clause</param>
		/// <returns>SelectQueryStatement</returns>
		public SelectQueryStatement GroupBy(params DbColumnView[] columns) {
			Groups = columns;
			return this;
		}
		/// <summary>
		/// Sum clause
		/// </summary>
		/// <param name="columns">The list of columns in sum clause</param>
		/// <returns></returns>
		public SelectQueryStatement Sum(params DbColumnView[] columns) {
			Sums = columns;
			return this;
		}
		/// <summary>
		/// Join clause in select statement
		/// </summary>
		/// <param name="jointStatement">JoinStatement</param>
		/// <exception cref="ArgumentNullException">throw when jointStatement is null</exception>
		/// <returns>SelectQueryStatement</returns>
		public SelectQueryStatement Join(JoinStatement jointStatement) {
			if (jointStatement == null) throw new ArgumentNullException("jointStatement");
			jointStatement.Statement = this;
			jointStatement.Root = Root;
			Joints.Add(jointStatement);
			return this;
		}
		/// <summary>
		/// Join clause in select statement
		/// </summary>
		/// <param name="table">joined table</param>
		/// <param name="joinExpr">join condition</param>
		/// <exception cref="ArgumentNullException">throw when joined table is null</exception>
		/// <returns>SelectQueryStatement</returns>
		public SelectQueryStatement Join(GlobalEntityView table, QueryExpBuilder joinExpr) {
			if(table==null)throw  new ArgumentNullException("table");
			return Join(new JoinStatement(table, joinExpr));
		}
		/// <summary>
		/// Join clause in select statement
		/// </summary>
		/// <param name="table">joined table</param>
		/// <param name="first">First column in join condition. The column must be belong to the table in select statment or the joined table</param>
		/// <param name="queryOperator">QueryOperator in join condition</param>
		/// <param name="second">Second column in join condition. The column must be belong to the joined table or the table in select statment</param>
		/// <exception cref="ArgumentNullException">Throw where joined table is null or first is null or second is null</exception>
		/// <returns>SelectQueryStatement</returns>
		public SelectQueryStatement Join(GlobalEntityView table, DbColumnView first, QueryOperator queryOperator, DbColumnView second) {
			return Join(table, new QueryExpBuilder(first, queryOperator, second));
		}
		/// <summary>
		/// Where expession
		/// </summary>
		/// <param name="whereExpression">Where clause in select statement</param>
		/// <returns>SelectQueryStatement</returns>
		public SelectQueryStatement Where(QueryExpBuilder whereExpression) {
			if (whereExpression != null) {
				whereExpression.Statement = this;
				foreach (var expressionBuilder in whereExpression.Builders) {
					expressionBuilder.Statement = this;
				}
				WhereExpression = whereExpression;
			}
			return this;
		}
		/// <summary>
		/// Order clause
		/// </summary>
		/// <param name="orders">The list of order clauses</param>
		/// <returns>SelectQueryStatement</returns>
		public SelectQueryStatement OrderBy(params  OrderStatement[] orders) {
			foreach (var orderStatement in orders) {
				orderStatement.Statement = this;
				Orders.Add(orderStatement);
			}
			return this;
		}
		/// <summary>
		/// Order clause
		/// </summary>
		/// <param name="column">Order column</param>
		/// <param name="order">Order type</param>
		/// <returns>SelectQueryStatement</returns>
		public SelectQueryStatement OrderBy(DbColumnView column, QueryOrder order) {
			var statement = new OrderStatement(column, order) { Statement = this };
			Orders.Add(statement);
			return this;
		}
		/// <summary>
		/// Order clause
		/// </summary>
		/// <param name="column">Order column default ASC order</param>
		/// <returns></returns>
		public SelectQueryStatement OrderBy(DbColumnView column) {
			return OrderBy(column, QueryOrder.Asc);
		}

	}
}
